<template>
  <div class="gym-dashboard">
    <!-- 顶部导航组件 -->
    <AppHeader />

    <!-- 装饰性背景元素 -->
    <div class="decorative-element top-left"></div>
    <div class="decorative-element top-right"></div>
    <div class="decorative-element bottom-left"></div>
    <div class="decorative-element bottom-right"></div>

    <!-- 登录模态框 -->
    <LoginModal
        v-model:show="showLoginModal"
        @showRegister="showRegisterModal = true"
    />

    <!-- 移除全局购买成功提示，移到模态框内 -->

    <RegisterModal
        v-model:show="showRegisterModal"
        @showLogin="showLoginModal = true"
    />

    <!-- 公告列表模态框 -->
    <div v-if="showAnnouncementsModal" class="modal-overlay" @click="showAnnouncementsModal = false">
      <div class="modal-content announcements-modal" @click.stop>
        <div class="modal-header">
          <div class="modal-icon">
            <i class="fa fa-bullhorn"></i>
          </div>
          <h3>系统公告</h3>
          <button class="close-btn" @click="showAnnouncementsModal = false">&times;</button>
        </div>

        <!-- 搜索框 -->
        <div class="search-box">
          <div class="input-with-icon">
            <i class="fa fa-search"></i>
            <input
                v-model="searchKeyword"
                type="text"
                placeholder="搜索公告标题或内容..."
                @input="filterAnnouncements"
            />
          </div>
        </div>

        <!-- 加载状态 -->
        <div v-if="loadingAnnouncements" class="loading-announcements">
          <div class="loading-spinner"><i class="fa fa-spinner fa-spin"></i></div>
          <p>加载公告中...</p>
        </div>

        <!-- 错误信息 -->
        <div v-else-if="announcementError" class="announcement-error">
          <i class="fa fa-exclamation-circle"></i>
          <p>{{ announcementError }}</p>
          <button class="btn small" @click="showAnnouncements">重试</button>
        </div>

        <!-- 公告列表 -->
        <div v-else class="announcements-list">
          <div
              v-for="announcement in filteredAnnouncements"
              :key="announcement.id"
              class="announcement-item"
          >
            <div class="announcement-main">
              <div class="announcement-header">
                <h4 class="announcement-title">{{ announcement.title }}</h4>
                <span class="announcement-type" :class="getTypeClass(announcement.type)">
                  {{ getTypeText(announcement.type) }}
                </span>
              </div>
              <p class="announcement-content-preview">{{ getContentPreview(announcement.content) }}</p>
              <div class="announcement-meta">
                <span class="announcement-date">
                  <i class="fa fa-clock"></i>
                  {{ formatDate(announcement.createdAt) }}
                </span>
              </div>
            </div>
            <button class="view-detail-btn" @click="viewAnnouncementDetail(announcement)">
              <i class="fa fa-eye"></i>
              查看详细
            </button>
          </div>
        </div>

        <div v-if="filteredAnnouncements.length === 0" class="no-announcements">
          <i class="fa fa-inbox"></i>
          <p>{{ searchKeyword ? '未找到相关公告' : '暂无公告' }}</p>
        </div>
      </div>
    </div>

    <!-- 会员卡购买模态框 -->
    <div v-if="showMemberCardModal" class="modal-overlay" @click="showMemberCardModal = false">
      <div class="modal-content member-card-modal" @click.stop>
        <div class="modal-header">
          <div class="modal-icon">
            <i class="fa fa-credit-card"></i>
          </div>
          <h3>选择会员卡</h3>
          <button class="close-btn" @click="showMemberCardModal = false">&times;</button>
        </div>
        <div class="modal-body">
          <!-- 购买成功提示 -->
          <div v-if="showPurchaseSuccess" class="success-message">
            <i class="fa fa-check-circle"></i>
            <span>购买成功！系统将在1秒后自动刷新...</span>
          </div>
          <!-- 错误提示 -->
          <div v-if="errorMessage" class="error-message">
            <i class="fa fa-exclamation-circle"></i>
            <span>{{ errorMessage }}</span>
          </div>
          <div class="member-card-options scrollable-list">
            <div v-if="loadingCardTypes" class="loading-cards">
              <div class="loading-spinner"><i class="fa fa-spinner fa-spin"></i></div>
              <p>加载会员卡类型中...</p>
            </div>
            <div v-else-if="memberCardTypes.length === 0" class="no-cards">
              <i class="fa fa-credit-card"></i>
              <p>暂无可购买的会员卡</p>
            </div>
            <div
                v-for="card in memberCardTypes"
                :key="card.id || card.cardId"
                class="card-type-item"
                :class="getCardTypeClass(card.cardName || card.name)"
            >
              <div class="card-type-icon">
                <i :class="getCardIcon(card.cardName || card.name)"></i>
              </div>
              <div class="card-type-content">
                <div class="card-type-header">
                  <span class="card-type-name">{{ card.cardName || card.name }}</span>
                  <span class="card-type-price">¥{{ card.price || card.cardPrice }}</span>
                </div>
                <div class="card-type-details">
                  <span class="card-duration">{{ getCardDuration(card.cardName || card.name) }}天有效期</span>
                  <span class="card-points">{{ card.points || '0积分' }}</span>
                </div>
              </div>
              <button class="purchase-btn-primary" @click="handlePurchaseConfirm(card)">
                立即购买
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 公告详情模态框 -->
    <div v-if="showAnnouncementDetailModal" class="modal-overlay" @click="showAnnouncementDetailModal = false">
      <div class="modal-content announcement-detail-modal" @click.stop>
        <div class="modal-header">
          <div class="modal-icon">
            <i class="fa fa-file-alt"></i>
          </div>
          <h3>公告详情</h3>
          <button class="close-btn" @click="showAnnouncementDetailModal = false">&times;</button>
        </div>

        <!-- 加载状态 -->
        <div v-if="loadingAnnouncements" class="loading-announcements">
          <div class="loading-spinner"><i class="fa fa-spinner fa-spin"></i></div>
          <p>加载公告详情中...</p>
        </div>

        <!-- 公告详情 -->
        <div v-else-if="currentAnnouncement" class="announcement-detail">
          <div class="detail-header">
            <h2 class="detail-title">{{ currentAnnouncement.title }}</h2>
            <span class="detail-type" :class="getTypeClass(currentAnnouncement.type)">
              {{ getTypeText(currentAnnouncement.type) }}
            </span>
          </div>

          <div class="detail-meta">
            <span class="detail-date">
              <i class="fa fa-clock"></i>
              发布时间：{{ formatDate(currentAnnouncement.createdAt) }}
            </span>
          </div>

          <div class="detail-content">
            <p>{{ currentAnnouncement.content }}</p>
          </div>
        </div>
      </div>
    </div>

    <!-- 横幅展示区 -->
    <section class="hero-section">
      <!-- 静态背景图片 -->
      <div class="hero-image-static"></div>
      <div class="hero-overlay"></div>
      <div class="hero-content">
        <h1>欢迎来到课程预约系统</h1>
        <p class="hero-subtitle">让运动成为习惯，让健康常伴左右</p>
        <!-- 单张图片 -->
        <div class="hero-buttons">
          <button class="btn primary" @click="handleReservation">立即预约</button>
          <button class="btn secondary" @click="showAnnouncements">查看公告</button>
          <button class="btn tertiary" @click="goToCourseList">查看课程</button>
          <button class="btn tertiary" @click="goToCoachList">查看教练</button>
        </div>
      </div>
    </section>

    <!-- 核心功能卡片区 -->
    <section class="cards-section">
      <!-- 会员卡卡片 -->
      <div class="card">
        <h2>我的会员卡</h2>
        <div class="card-content">
          <!-- 未登录时显示会员卡类型列表 -->
          <div v-if="!isLoggedIn" class="card-types-container">
            <div class="card-types-list ranking-list">
              <div
                  v-for="cardType in memberCardTypes"
                  :key="cardType.cardTypeId"
                  class="card-type-item"
                  :class="getCardTypeClass(cardType.cardName)"
              >
                <div class="card-type-icon">
                  <i :class="getCardIcon(cardType.cardName)"></i>
                </div>
                <div class="card-type-content">
                  <div class="card-type-header">
                    <span class="card-type-name">{{ cardType.cardName }}</span>
                    <span class="card-type-price">¥{{ cardType.price }}</span>
                  </div>
                  <div class="card-type-details">
                    <span class="card-duration">{{ cardType.durationDays }}天有效期</span>
                    <span class="card-points">{{ cardType.points }}</span>
                  </div>
                </div>
              </div>
            </div>
            <div class="login-prompt">
              <p class="expire-date">请登录后查看详情和购买</p>
            </div>
          </div>

          <!-- 登录后显示会员卡信息 -->
          <div v-else-if="loadingMemberCard" class="balance-info-alone">
            <div class="loading-content">
              <p class="balance-label">加载中...</p>
            </div>
          </div>
          <div v-else class="balance-info-alone">
            <!-- 滚动内容区域 -->
            <div class="member-card-scrollable">
              <!-- 会员卡信息容器 -->
              <div v-if="userValidCards && userValidCards.length > 0 && latestValidCard && latestValidCard.remainingDays > 0" class="membership-info-container">
                <div class="card-info-box">
                  <!-- 剩余天数和到期日期并排显示 -->
                  <div class="card-info-row">
                    <div class="remaining-days-section">
                      <div class="remaining-days-value">{{ latestValidCard.remainingDays }}</div>
                      <div class="remaining-days-label">剩余天数</div>
                    </div>

                    <div class="expiry-date-section">
                      <div class="expiry-date-value">{{ formatExpireDate(latestValidCard.endDate) }}</div>
                      <div class="expiry-date-label">到期日期</div>
                      <!-- 购买新卡按钮放在到期日期下方 -->
                      <button class="btn renew-btn mini-btn" @click="goToMemberCardPurchase">
                        <i class="fa fa-refresh"></i>
                        {{ latestValidCard.remainingDays <= 7 ? '续费' : '购卡' }}
                      </button>
                    </div>
                  </div>
                </div>
              </div>

              <!-- 没有有效会员卡的情况 -->
              <div v-else class="membership-info-container">
                <div class="card-info-box relative">
                  <!-- 开通会员按钮放在右上角 -->
                  <button class="btn purchase-btn-primary mini-btn absolute top-2 right-2" @click="goToMemberCardPurchase">
                    <i class="fa fa-plus"></i>
                    开通会员
                  </button>
                  <div class="no-card-content">
                    <div class="no-card-icon">
                      <i class="fa fa-credit-card"></i>
                    </div>
                    <p class="no-card-text">您还未开通会员卡或已到期</p>
                  </div>
                </div>
              </div>

              <!-- 显示用户积分和等级信息 -->
              <div class="user-points-info">
                <div class="points-header">
                  <i class="fa fa-star"></i>
                  <span>我的积分</span>
                </div>
                <div class="points-content">
                  <div class="points-value-section" style="display: flex; align-items: center; gap: 10px;">
                    <span class="points-value">{{ userPoints || 0 }}</span>
                    <span class="points-unit">积分</span>
                  </div>
                  <div class="level-section">
                    <div class="member-level-badge" :class="getLevelClass(userPoints || 0)">
                      <i class="fa fa-crown"></i>
                      {{ getMemberLevel(userPoints || 0) }}
                    </div>
                    <div class="level-progress">
                      <div class="progress-bar">
                        <div class="progress-fill" :style="{ width: getLevelProgress(userPoints || 0) + '%' }"></div>
                      </div>
                      <span class="progress-text">下一等级: {{ getNextLevel(userPoints || 0) }}</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 即将开始课程卡片 -->
      <div class="card">
        <h2>即将开始课程</h2>
        <div v-if="loadingCourses" class="loading-courses">
          <p>加载中...</p>
        </div>
        <div v-else-if="upcomingCourses.length > 0" class="upcoming-courses-container">
          <div class="upcoming-courses-list">
            <div
                v-for="course in upcomingCourses"
                :key="course.cId"
                class="course-item"
            >
              <div class="course-info">
                <h4 class="course-name">{{ course.cName }}</h4>
                <p class="course-time">
                  <i class="fa fa-clock"></i>
                  {{ formatCourseTime(course.cTime) }}
                </p>
                <p class="course-details">
                  <span class="course-grade">{{ course.cGrade }}</span>
                  <span class="course-capacity">已预约: {{ course.cCurrent }}/{{ course.cMax }}</span>
                </p>
              </div>
            </div>
          </div>
        </div>
        <div v-else class="no-courses">
          <p class="card-subtitle">暂无即将开始的课程</p>
          <button class="btn small" @click="goToCourseList">查看所有课程</button>
        </div>
      </div>

      <!-- 运动排行榜卡片 -->
      <div class="card">
        <div class="card-header-with-search">
          <h2>运动排行榜</h2>
          <!-- 搜索框放在右上角 -->
          <div class="ranking-search-box">
            <div class="input-with-icon">
              <i class="fa fa-search"></i>
              <input
                  v-model="rankingSearchKeyword"
                  type="text"
                  placeholder="搜索昵称..."
                  @input="filterRanking"
              />
            </div>
          </div>
        </div>
        <div v-if="loadingRanking" class="loading-courses">
          <p>加载中...</p>
        </div>
        <div v-else class="ranking-content">
          <ul v-if="filteredRanking.length > 0" class="ranking-list">
            <li
                v-for="(user, index) in filteredRanking"
                :key="user.userId || index"
                class="rank-item"
            >
              <!-- 排名数字放在左边 -->
              <span class="ranking-number">
                {{ getRankingNumber(index, user.uPoints) }}
              </span>
              <div class="user-info">
                <img
                    :src="`https://picsum.photos/40/40?person=${index + 1}`"
                    alt="用户头像"
                    class="avatar"
                />
                <div class="user-details">
                  <span class="user-nickname">{{ user.uNickname || '匿名用户' }}</span>
                  <div class="member-level">{{ getMemberLevel(user.uPoints) }}</div>
                </div>
              </div>
            </li>
          </ul>
          <div v-else class="no-courses">
            <p>{{ rankingSearchKeyword ? '未找到相关用户' : '暂无排行榜数据' }}</p>
          </div>
        </div>
      </div>
    </section>

    <!-- 水印 -->
    <div class="watermark">健身房会员与预约管理系统</div>

    <!-- 添加页脚 -->
    <AppFooter />
  </div>
</template>

<script>
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useUserStore } from '@/stores/auth'
import axios from 'axios'
import AppFooter from '@/components/common/AppFooter.vue'
import AppHeader from '@/components/common/AppHeader.vue'
import LoginModal from '@/components/auth/LoginModal.vue'
import RegisterModal from '@/components/auth/RegisterModal.vue'
import { getAnnouncements, getAnnouncementDetail } from '@/api/announcement'

export default {
  name: 'GymDashboard',
  components: {
    AppHeader,
    AppFooter,
    LoginModal,
    RegisterModal
  },
  setup() {
    const router = useRouter()
    const route = useRoute()
    const userStore = useUserStore()
    const showLoginModal = ref(false)
    const showRegisterModal = ref(false)
    const showAnnouncementsModal = ref(false)
    const showAnnouncementDetailModal = ref(false)

    // 登录状态
    const isLoggedIn = ref(false)

    // 会员卡类型数据
    const memberCardTypes = ref([])
    const loadingCardTypes = ref(false)

    // 用户会员卡信息
    const userMemberCard = ref(null)
    const loadingMemberCard = ref(false)
    const userPoints = ref(0)
    // 存储用户所有有效会员卡
    const userValidCards = ref([])

    const loginForm = ref({
      mobile: '',
      password: ''
    })
    const registerForm = ref({
      mobile: '',
      password: '',
      nickname: ''
    })
    const errorMessage = ref('')
    const registerErrorMessage = ref('')
    const rememberMe = ref(false)
    const searchKeyword = ref('')

    // 即将开始课程相关状态
    const upcomingCourses = ref([])
    const loadingCourses = ref(false)

    // 用户排行榜相关状态
    const userRanking = ref([])
    const loadingRanking = ref(false)

    // 跳转到后台登录页面的方法
    const goToAdminLogin = () => {
      console.log('跳转到后台登录页面')
      router.push('/admin/login')
    }

    // 使用 window.open 在新标签页打开
    const goToAdminLoginNewTab = () => {
      const route = router.resolve({ name: 'AdminLogin' })
      window.open(route.href, '_blank')
    }

    // 公告相关
    const announcements = ref([])
    const currentAnnouncement = ref(null)
    const loadingAnnouncements = ref(false)
    const announcementError = ref(null)

    // 模拟公告数据
    const mockAnnouncements = [
      {
        id: 1,
        title: '系统维护通知',
        content: '为了提供更好的服务，我们将在本周六凌晨2:00-4:00进行系统维护。维护期间系统将无法访问，给您带来的不便敬请谅解。感谢您的支持！',
        type: 'maintenance',
        status: 1,
        createdAt: '2024-01-15T10:00:00'
      },
      {
        id: 2,
        title: '春节营业时间调整',
        content: '尊敬的会员：春节期间（2月10日-2月17日）我们的营业时间将调整为9:00-18:00。2月18日起恢复正常营业时间。祝大家春节快乐，身体健康！',
        type: 'notice',
        status: 1,
        createdAt: '2024-01-10T14:30:00'
      },
      {
        id: 3,
        title: '新课程上线 - 瑜伽普拉提',
        content: '我们很高兴地宣布，新的瑜伽普拉提课程现已上线！课程结合了瑜伽的柔美与普拉提的力量训练，适合各个年龄段的会员。欢迎前来体验！课程特点：1. 专业教练指导 2. 小班教学 3. 个性化调整 4. 改善体态和核心力量',
        type: 'course',
        status: 1,
        createdAt: '2024-01-08T09:15:00'
      },
      {
        id: 4,
        title: '会员优惠活动',
        content: '即日起至本月底，新办理年卡会员可享受8折优惠，并赠送私人教练体验课一节。老会员推荐新会员成功办卡，双方均可获得一个月会籍延长。详情请咨询前台。',
        type: 'promotion',
        status: 1,
        createdAt: '2024-01-05T16:45:00'
      },
      {
        id: 5,
        title: '新增健身器材通知',
        content: '为提升会员健身体验，我们新引进了10台高端跑步机和5套力量训练设备。所有设备均已调试完成，欢迎各位会员前来体验使用。',
        type: 'equipment',
        status: 1,
        createdAt: '2024-01-03T11:20:00'
      },
      {
        id: 6,
        title: '团体课程时间调整',
        content: '自下周一起，团体课程时间将进行调整：早晨瑜伽课调整为7:00-8:00，晚间动感单车课调整为19:30-20:30。请各位会员注意课程时间变化。',
        type: 'course',
        status: 1,
        createdAt: '2024-01-02T15:40:00'
      },
      {
        id: 7,
        title: '游泳池清洁维护',
        content: '为保障游泳池水质卫生，本周四（1月18日）游泳池将进行全天的清洁维护工作，届时暂停开放。周五恢复正常使用。',
        type: 'maintenance',
        status: 1,
        createdAt: '2024-01-01T09:00:00'
      },
      {
        id: 8,
        title: '私人教练团队扩充',
        content: '我们很高兴地宣布，本月新增3名专业私人教练加入我们的团队。他们分别在力量训练、康复训练和体能提升方面有着丰富的经验。欢迎预约体验课！',
        type: 'coach',
        status: 1,
        createdAt: '2023-12-28T14:15:00'
      }
    ]

    // 计算属性和工具函数
    const filteredAnnouncements = computed(() => {
      if (!searchKeyword.value) {
        return announcements.value
      }
      const keyword = searchKeyword.value.toLowerCase()
      return announcements.value.filter(announcement =>
          announcement.title.toLowerCase().includes(keyword) ||
          announcement.content.toLowerCase().includes(keyword)
      )
    })

    const latestValidCard = computed(() => {
      // 直接使用从用户信息获取的uRt数据，不再处理卡片逻辑
      if (userValidCards.value && userValidCards.value.length > 0 && userValidCards.value[0].uRt !== undefined) {
        const remainingDays = userValidCards.value[0].uRt;
        
        // 计算到期日期
        const expireDate = new Date();
        expireDate.setDate(expireDate.getDate() + remainingDays);
        
        console.log('使用用户uRt数据作为剩余天数:', remainingDays)
        
        return {
          remainingDays: remainingDays,
          endDate: formatDate(expireDate)
        };
      }
      
      // 如果没有数据，返回默认值
      return {
        remainingDays: 0,
        endDate: ''
      };
    })

    const getTypeClass = (type) => {
      const typeMap = {
        maintenance: 'type-maintenance',
        notice: 'type-notice',
        course: 'type-course',
        promotion: 'type-promotion',
        equipment: 'type-equipment',
        coach: 'type-coach'
      }
      return typeMap[type] || 'type-default'
    }

    const getTypeText = (type) => {
      const typeMap = {
        maintenance: '系统维护',
        notice: '通知',
        course: '课程',
        promotion: '优惠',
        equipment: '器材',
        coach: '教练'
      }
      return typeMap[type] || '公告'
    }

    const getContentPreview = (content) => {
      return content.length > 60 ? content.substring(0, 60) + '...' : content
    }

    const formatDate = (dateString) => {
      const date = new Date(dateString)
      return date.toLocaleDateString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit'
      })
    }

    // 新增：格式化课程时间
    const formatCourseTime = (timeString) => {
      if (!timeString) return '时间待定'
      try {
        const date = new Date(timeString)
        if (isNaN(date.getTime())) return '时间待定'
        
        // 格式化年月日
        const year = date.getFullYear()
        const month = (date.getMonth() + 1).toString().padStart(2, '0')
        const day = date.getDate().toString().padStart(2, '0')
        const dateText = `${year}年${month}月${day}日`
        
        // 格式化星期
        const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
        const weekdayText = weekdays[date.getDay()]
        
        // 格式化时间
        const hours = date.getHours().toString().padStart(2, '0')
        const minutes = date.getMinutes().toString().padStart(2, '0')
        const timeText = `${hours}:${minutes}`
        
        return `${dateText} ${weekdayText} ${timeText}`
      } catch (error) {
        console.error('时间格式化错误:', error)
        return '时间待定'
      }
    }

    // 新增：格式化过期日期
    const formatExpireDate = (dateString) => {
      if (!dateString) return '暂无'
      const date = new Date(dateString)
      return date.toLocaleDateString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit'
      })
    }

    // 新增：计算会员卡剩余天数
    const getRemainingDays = (expireDate) => {
      if (!expireDate) return 0

      const now = new Date()
      const expire = new Date(expireDate)

      // 确保日期对象有效
      if (isNaN(expire.getTime())) {
        console.error('无效的过期日期:', expireDate)
        return 0
      }

      // 计算毫秒差
      const diffTime = expire.getTime() - now.getTime()

      // 转换为天数并向上取整
      const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))

      console.log('计算剩余天数:', {
        expireDate,
        now: now.toISOString(),
        expire: expire.toISOString(),
        diffTime,
        diffDays
      })

      // 如果已经过期，返回0
      return Math.max(0, diffDays)
    }

    // 获取会员等级
    const getMemberLevel = (points) => {
      if (points === undefined || points === null) return '普通用户'
      if (points === 0) return '普通用户'
      if (points > 0 && points < 99) return '初级会员'
      if (points >= 99 && points < 399) return '中级会员'
      if (points >= 399) return '高级会员'
      return '普通用户'
    }

    // 获取等级进度
    const getLevelProgress = (points) => {
      if (points >= 399) return 100
      if (points >= 99) return Math.min(100, ((points - 99) / 300) * 100)
      return Math.min(100, (points / 99) * 100)
    }

    // 获取下一等级
    const getNextLevel = (points) => {
      if (points < 99) return '初级会员'
      if (points < 399) return '高级会员'
      return '最高等级'
    }

    // 获取等级CSS类名
    const getLevelClass = (points) => {
      const level = getMemberLevel(points)
      const classMap = {
        '初级会员': 'level-初级会员',
        '中级会员': 'level-中级会员',
        '高级会员': 'level-高级会员'
      }
      return classMap[level] || ''
    }

    // 获取排名序号
    const getRankingNumber = (index, points) => {
      // 如果当前用户积分是0
      if (points === 0) {
        // 检查是否有前面的用户积分也是0
        if (index > 0 && userRanking.value[index - 1].uPoints === 0) {
          return '--'
        }
        // 检查是否有后面的用户积分也是0
        if (index < userRanking.value.length - 1 && userRanking.value[index + 1].uPoints === 0) {
          return '--'
        }
      }
      return index + 1
    }

    // 根据卡类型名称获取积分
    const getCardPoints = (cardName) => {
      const pointsMap = {
        '月卡': '+30积分',
        '季卡': '+100积分',
        '年卡': '+420积分'
      }
      return pointsMap[cardName] || ''
    }

    // 根据卡类型获取CSS类名
    const getCardTypeClass = (cardName) => {
      const classMap = {
        '月卡': 'month-card',
        '季卡': 'season-card',
        '年卡': 'year-card',
        '体验卡': 'default-card'
      }
      return classMap[cardName] || 'default-card'
    }

    // 根据卡类型获取图标
    const getCardIcon = (cardName) => {
      const iconMap = {
        '月卡': 'fa fa-calendar',
        '季卡': 'fa fa-calendar-check-o',
        '年卡': 'fa fa-star',
        '体验卡': 'fa fa-gift'
      }
      return iconMap[cardName] || 'fa fa-credit-card'
    }

    const filterAnnouncements = () => {
      // 计算属性会自动更新
    }

    // 处理预约按钮点击
    const handleReservation = () => {
      console.log('=========== handleReservation 执行 ===========');
      if (userStore.getIsLoggedIn) {
        console.log('登录状态确认，跳转到课程列表');
        router.push('/course/list')
      } else {
        console.log('未登录，显示登录模态框');
        showLoginModal.value = true
      }
    }

    // 登录状态管理函数
    const checkAndValidateLoginStatus = async () => {
      console.log('GymDashboard - 检查登录状态')

      if (userStore.getIsLoggedIn) {
        console.log('GymDashboard - 从userStore确认已登录')
        isLoggedIn.value = true
        await fetchUserMemberCard()
        return true
      }

      const token = localStorage.getItem('userToken')
      const userInfoStr = localStorage.getItem('userInfo')

      console.log('GymDashboard - 从localStorage获取状态:', { token: !!token, userInfo: !!userInfoStr })

      if (!token || !userInfoStr) {
        console.log('GymDashboard - 无登录信息')
        isLoggedIn.value = false
        userMemberCard.value = null
        userValidCards.value = []
        return false
      }

      try {
        const userInfo = JSON.parse(userInfoStr)

        const hasValidUserInfo = userInfo && (
            userInfo.userId ||
            userInfo.id ||
            userInfo.uId ||
            userInfo.mobile
        )

        const isValidToken = token && token.trim() !== ''

        console.log('GymDashboard - 登录信息验证结果:', { hasValidUserInfo, isValidToken })

        if (hasValidUserInfo && isValidToken) {
          console.log('GymDashboard - 登录状态有效，更新store')
          userStore.token = token
          userStore.isLoggedIn = true
          userStore.userInfo = userInfo

          isLoggedIn.value = true
          await fetchUserMemberCard()
          return true
        } else {
          console.log('GymDashboard - 登录信息无效')
          if (!hasValidUserInfo || !isValidToken) {
            clearLoginData()
          }
          isLoggedIn.value = false
          userMemberCard.value = null
          userValidCards.value = []
          return false
        }
      } catch (error) {
        console.error('GymDashboard - 验证登录状态失败:', error)
        if (error instanceof SyntaxError) {
          clearLoginData()
        }
        isLoggedIn.value = false
        userMemberCard.value = null
        userValidCards.value = []
        return false
      }
    }

    // 清理登录数据的函数
    const clearLoginData = () => {
      console.log('GymDashboard - 清理登录数据')
      localStorage.removeItem('userToken')
      localStorage.removeItem('userInfo')
      localStorage.removeItem('userId')
      userStore.token = null
      userStore.isLoggedIn = false
      userStore.userInfo = null
      console.log('GymDashboard - 登录数据已清理，store状态:', { storeLoggedIn: userStore.isLoggedIn })
    }

    // 获取会员卡类型 - 修改为获取所有类型
    const fetchMemberCardTypes = async () => {
      loadingCardTypes.value = true
      try {
        console.log('开始获取会员卡类型数据...')

        const response = await axios.get('/api/member-card-type/available')
        console.log('会员卡类型API响应:', response.data)

        let cardData = []

        if (response.data && response.data.success === true) {
          cardData = response.data.data || []
        } else if (Array.isArray(response.data)) {
          cardData = response.data
        } else if (response.data && response.data.data) {
          cardData = response.data.data
        }

        console.log('获取到的会员卡数据:', cardData)

        if (Array.isArray(cardData)) {
          memberCardTypes.value = cardData.map(card => ({
            ...card,
            durationDays: getDurationDaysByCardName(card.cardName),
            points: getPointsByCardName(card.cardName)
          }))
          console.log('处理后的会员卡数据:', memberCardTypes.value)

          if (cardData.length === 0) {
            console.log('后端返回会员卡数据为空数组')
          }
        } else {
          console.warn('会员卡API返回格式异常，使用模拟数据作为后备方案')
          memberCardTypes.value = getMockCardTypes()
        }
      } catch (error) {
        console.error('获取会员卡类型失败:', error)
        if (error.response) {
          console.error('API错误响应:', error.response.status, error.response.data)
        } else if (error.request) {
          console.error('网络错误，没有收到响应:', error.request)
        }
      } finally {
        loadingCardTypes.value = false
      }
    }

    // 根据卡名称获取有效期天数
    const getDurationDaysByCardName = (cardName) => {
      const durationMap = {
        '月卡': 30,
        '季卡': 90,
        '年卡': 365,
        '体验卡': 1
      }
      return durationMap[cardName] || 30
    }

    // 根据卡名称获取积分
    const getPointsByCardName = (cardName) => {
      const pointsMap = {
        '月卡': '+30积分',
        '季卡': '+100积分',
        '年卡': '+420积分',
        '体验卡': ''
      }
      return pointsMap[cardName] || ''
    }

    // 获取用户排行榜 - 修改为获取所有用户
    const fetchUserRanking = async () => {
      loadingRanking.value = true
      try {
        const response = await axios.get('/api/users/ranking')

        console.log('完整响应:', response)
        console.log('响应数据:', response.data)

        let rankingData = []

        if (response.data && response.data.success === true) {
          rankingData = response.data.data || []
        } else if (Array.isArray(response.data)) {
          rankingData = response.data
        } else if (response.data && response.data.data) {
          rankingData = response.data.data
        }

        console.log('提取的排行榜数据:', rankingData)

        if (Array.isArray(rankingData)) {
          rankingData.sort((a, b) => (b.uPoints || 0) - (a.uPoints || 0))
          userRanking.value = rankingData
        } else {
          console.error('排行榜数据格式错误:', rankingData)
          userRanking.value = getMockRankingData()
        }
      } catch (error) {
        console.error('获取用户排行榜失败:', error)
      } finally {
        loadingRanking.value = false
      }
    }

    // 获取即将开始的课程
    const fetchUpcomingCourses = async () => {
      loadingCourses.value = true
      try {
        const response = await axios.get('/api/courses/available')

        if (response.data && Array.isArray(response.data)) {
          const now = new Date()
          const futureCourses = response.data
              .filter(course => {
                if (!course.cTime) return false
                const courseTime = new Date(course.cTime)
                return courseTime > now && course.cStatus === 1
              })
              .sort((a, b) => new Date(a.cTime) - new Date(b.cTime))

          upcomingCourses.value = futureCourses
        } else {
          upcomingCourses.value = []
        }
      } catch (error) {
        console.error('获取课程失败:', error)
        upcomingCourses.value = []
      } finally {
        loadingCourses.value = false
      }
    }

    // 跳转到课程详情
    const goToCourseDetail = (courseId) => {
      router.push(`/course/detail/${courseId}`)
    }

    // 会员卡选项
    const cardOptions = [
      { id: 1, name: '月卡', price: 99, points: 30 },
      { id: 2, name: '季卡', price: 299, points: 100 },
      { id: 3, name: '年卡', price: 1299, points: 420 }
    ]

    // 显示会员卡购买模态框
    const showMemberCardModal = ref(false)
    const showPurchaseSuccess = ref(false)

    const goToMemberCardPurchase = () => {
      console.log('开通会员按钮被点击，直接显示购买模态框')
      // 直接显示模态框，不依赖API调用
      showMemberCardModal.value = true
      // 异步获取会员卡数据，不阻塞模态框显示
      fetchMemberCardTypes().catch(err => {
        console.error('获取会员卡数据失败:', err)
        errorMessage.value = '获取会员卡数据失败，请稍后重试'
      })
    }

    // 根据卡片名称获取有效期天数
    const getCardDuration = (cardName) => {
      if (!cardName) return 30

      // 标准化卡片名称以便匹配
      const normalizedName = cardName.replace(/[度]?[卡]$/, '').toLowerCase()

      // 根据不同卡片类型返回对应的有效期天数
      // 与后端保持一致的固定天数计算
      if (normalizedName.includes('月')) return 31
      if (normalizedName.includes('季')) return 91
      if (normalizedName.includes('年')) return 366
      if (normalizedName.includes('体验')) return 1
      return 30
    }

    // 新增：处理购买确认
    const handlePurchaseConfirm = (card) => {
      const cardName = card.cardName || card.name
      const cardPrice = card.price || card.cardPrice

      const isConfirmed = confirm(`您确定要购买【${cardName}】吗？价格为 ¥${cardPrice}`)

      if (isConfirmed) {
        purchaseMemberCard(card)
      }
    }

    // 会员卡购买
    const purchaseMemberCard = async (card) => {
      // 检查用户是否登录
      if (!userStore.isLoggedIn) {
        // 如果未登录，显示登录模态框
        showLoginModal.value = true
        return
      }

      const userId = localStorage.getItem('userId')
      if (!userId) {
        console.error('未找到用户ID')
        errorMessage.value = '用户信息不完整，请重新登录'
        return
      }

      try {
        // 准备购买数据，不再前端计算结束日期，由后端根据卡类型计算
        const purchaseData = {
          userId: parseInt(userId),
          cardTypeId: card.id || card.cardId || card.cardTypeId,
          purchasePrice: card.price || card.cardPrice || 0
        }

        console.log('发送会员卡购买请求:', purchaseData)

        // 发送购买请求到后端
        const response = await axios.post('/api/member-card-records/purchase', purchaseData)

        console.log('购买响应:', response.data)

        // 无论后端返回什么格式，我们都显示成功提示并执行后续操作
        console.log('设置showPurchaseSuccess为true')
        showPurchaseSuccess.value = true
        
        // 设置定时器，1秒后执行隐藏成功提示、关闭模态框和刷新页面
        console.log('设置setTimeout，1秒后执行刷新逻辑')
        setTimeout(() => {
          console.log('setTimeout回调执行')
          showPurchaseSuccess.value = false
          // 不再手动关闭模态框，因为页面即将刷新
          window.location.reload()
        }, 1000)
        
        // 处理后端响应
        if (response.data && response.data.success === true) {
          console.log('后端确认购买成功')
          // 异步获取用户数据，但不阻塞UI流程
          fetchUserMemberCard().catch(e => console.error('fetchUserMemberCard出错:', e))
        }
      } catch (error) {
        // 捕获网络或其他错误
        console.error('购买过程中发生错误:', error)
        
        // 购买失败时，确保不执行刷新逻辑
        showPurchaseSuccess.value = false
        
        if (error.response) {
          errorMessage.value = error.response.data?.message || '服务器错误，请稍后重试'
        } else if (error.request) {
          errorMessage.value = '无法连接到服务器，请检查网络连接'
        } else {
          errorMessage.value = '购买过程中发生错误，请稍后重试'
        }
      }
    }

    // 获取用户所有有效会员卡
    const fetchUserValidCards = async () => {
      if (!isLoggedIn.value) {
        return;
      }

      try {
        const userId = localStorage.getItem('userId');
        if (!userId) {
          console.error('未找到用户ID');
          return;
        }

        console.log('开始获取用户有效会员卡，用户ID:', userId);
        const response = await axios.get(`/api/member-card-records/valid/${userId}`);
        console.log('有效会员卡API响应:', response.data);

        // 根据Result类的格式处理响应数据
        if (response.data && response.data.code === 200 && response.data.data) {
          userValidCards.value = response.data.data;
          console.log('获取到的有效会员卡数量:', userValidCards.value.length);
          console.log('有效会员卡详情:', userValidCards.value);

          // 不再在前端计算剩余天数，直接使用后端返回的uRt字段
          userValidCards.value.forEach(card => {
            console.log(`卡 ${card.cardId} 后端返回的剩余天数(uRt):`, card.uRt);
            card.remainingDays = card.uRt || 0;
          });
        } else {
          console.log('响应格式不符合预期或请求失败:', response.data);
          // 尝试直接使用数据（兼容可能的直接返回列表情况）
          if (Array.isArray(response.data)) {
            userValidCards.value = response.data;
            userValidCards.value.forEach(card => {
              card.remainingDays = card.uRt || 0;
            });
          } else {
            userValidCards.value = [];
          }
        }
      } catch (error) {
        console.error('获取用户有效会员卡失败:', error);
        userValidCards.value = [];
      }
    }

    // 修改：获取用户会员卡信息和积分
    const fetchUserMemberCard = async () => {
      console.log('fetchUserMemberCard开始执行，登录状态:', isLoggedIn.value)
      if (!isLoggedIn.value) {
        console.log('用户未登录，退出函数')
        return
      }

      loadingMemberCard.value = true
      // 重置积分和会员卡信息，确保只显示最新的后端数据
      userPoints.value = 0
      userMemberCard.value = null
      userValidCards.value = [] // 重置有效会员卡列表

      try {
        const userId = localStorage.getItem('userId')
        console.log('获取到的userId:', userId)
        if (!userId) {
          console.error('未找到用户ID')
          loadingMemberCard.value = false
          return
        }

        // 直接从用户信息中获取uRt数据，不再使用卡片相关逻辑

        // 然后获取用户积分信息
        try {
          console.log('尝试从用户信息API获取积分，用户ID:', userId)
          const userInfoResponse = await axios.get(`/api/users/${userId}`)
          console.log('用户信息API响应:', userInfoResponse.data)

          if (userInfoResponse.data) {
            const userData = userInfoResponse.data.data || userInfoResponse.data
            console.log('用户数据:', userData)
            console.log('可能的积分字段:', {
              uPoints: userData.uPoints,
              points: userData.points,
              score: userData.score,
              totalPoints: userData.totalPoints,
              userScore: userData.userScore
            })

            // 获取积分信息
        userPoints.value = userData.uPoints || userData.points || userData.score || userData.totalPoints || userData.userScore || 0
        console.log('从用户信息API获取到积分:', userPoints.value)
        
        // 获取uRt数据作为剩余天数
        if (userData.uRt !== undefined) {
          userValidCards.value = [{ uRt: userData.uRt }]; // 为了兼容现有计算属性，保留一个简单对象
          console.log('从用户信息API获取到剩余天数(uRt):', userData.uRt)
        } else {
          console.warn('用户信息中未找到uRt字段')
        }
          }
        } catch (userInfoError) {
          console.warn('获取用户信息失败，继续尝试获取会员卡记录:', userInfoError)
        }

        // 同时获取所有会员卡记录用于积分信息（备用）
        try {
          console.log('尝试从会员卡记录API获取积分，用户ID:', userId)
          const response = await axios.get(`/api/member-card-records/user/${userId}`)
          console.log('会员卡记录API响应:', response.data)

          // 处理会员卡记录用于积分信息
          let records = []
          if (response.data && response.data.success === true) {
            records = response.data.data || []
          } else if (Array.isArray(response.data)) {
            records = response.data
          }

          console.log('获取到的会员卡记录数量:', records.length)

          // 如果有会员卡记录，使用记录中的积分信息
          if (records.length > 0 && userPoints.value === 0) {
            const latestRecord = records.sort((a, b) => new Date(b.createdAt || b.purchaseDate || 0) - new Date(a.createdAt || a.purchaseDate || 0))[0]

            console.log('最新会员卡记录详情:', latestRecord)
            console.log('记录中可能的积分字段:', {
              userPoints: latestRecord.userPoints,
              uPoints: latestRecord.uPoints,
              points: latestRecord.points,
              score: latestRecord.score
            })

            // 尝试更多可能的积分字段名
            const recordPoints = latestRecord.userPoints || latestRecord.uPoints || latestRecord.points || latestRecord.score || 0
            userPoints.value = recordPoints
            console.log('从会员卡记录获取积分:', userPoints.value)
          }
        } catch (recordsError) {
          console.error('获取会员卡记录失败:', recordsError)
        }

        console.log('最终用户积分（仅从后端获取）:', userPoints.value)
      } catch (error) {
        console.error('获取用户会员卡信息失败:', error)
        // 发生错误时不使用缓存，保持为0
        userPoints.value = 0
        userMemberCard.value = null
        userValidCards.value = []
      } finally {
        loadingMemberCard.value = false
        console.log('fetchUserMemberCard执行完成，最终积分:', userPoints.value)
      }
    }

    // 监听userStore的登录状态变化
    watch(() => userStore.getIsLoggedIn, (newStatus) => {
      console.log('GymDashboard - 监听登录状态变化:', '->', newStatus)

      isLoggedIn.value = newStatus

      if (newStatus) {
        fetchUserMemberCard()
      } else {
        userMemberCard.value = null
        userValidCards.value = []
        fetchMemberCardTypes()
      }
    }, { immediate: true })

    // 监听路由变化，确保每次回到首页都重新检查登录状态并加载会员卡信息
    watch(() => route.path, (newPath) => {
      console.log('GymDashboard - 路由变化:', newPath)
      // 强制刷新store状态，确保从localStorage恢复最新数据
      userStore.refreshStatus()
      // 重新检查登录状态并加载会员卡信息
      checkAndValidateLoginStatus()

      // 不使用localStorage缓存，积分将通过fetchUserMemberCard从后端获取
    }, { immediate: true })

    // 查看公告列表
    const showAnnouncements = async () => {
      try {
        loadingAnnouncements.value = true
        announcementError.value = null

        const response = await getAnnouncements()

        if (response.data && response.data.data) {
          announcements.value = response.data.data
        } else if (response.data) {
          announcements.value = response.data
        } else {
          announcements.value = mockAnnouncements
        }

        searchKeyword.value = ''
        showAnnouncementsModal.value = true
      } catch (error) {
        console.error('获取公告失败:', error)
        announcementError.value = '获取公告失败，请稍后重试'
        announcements.value = mockAnnouncements
        searchKeyword.value = ''
        showAnnouncementsModal.value = true
      } finally {
        loadingAnnouncements.value = false
      }
    }

    // 查看公告详情
    const viewAnnouncementDetail = async (announcement) => {
      announcementError.value = null

      try {
        currentAnnouncement.value = announcement
        showAnnouncementDetailModal.value = true

        try {
          const response = await getAnnouncementDetail(announcement.id)

          if (response.data && response.data.data) {
            currentAnnouncement.value = response.data.data
          } else if (response.data) {
            currentAnnouncement.value = response.data
          }
        } catch (updateError) {
          console.log('后台更新公告详情失败，但不影响用户查看:', updateError)
        }
      } catch (error) {
        console.error('显示公告详情异常:', error)
        currentAnnouncement.value = announcement
        showAnnouncementDetailModal.value = true
      } finally {
        loadingAnnouncements.value = false
      }
    }

    // 处理登录
    const handleLogin = async () => {
      console.log('GymDashboard - 处理登录')
      errorMessage.value = ''

      if (!loginForm.value.mobile.trim()) {
        errorMessage.value = '请输入手机号'
        return
      }

      if (!loginForm.value.password.trim()) {
        errorMessage.value = '请输入密码'
        return
      }

      try {
        const response = await axios.post('/api/users/login', {
          mobile: loginForm.value.mobile,
          password: loginForm.value.password
        })

        if (response.data && response.data.success) {
          let userData = response.data.data
          console.log('GymDashboard - 登录成功，用户数据:', userData)

          localStorage.setItem('userToken', userData.token || 'user-logged-in')

          try {
            const userId = userData.userId || userData.id
            if (userId) {
              console.log('GymDashboard - 调用getUserInfo获取最新用户信息，用户ID:', userId)
              const userInfoResponse = await axios.get(`/api/users/${userId}`)

              if (userInfoResponse.data && userInfoResponse.data.success) {
                userData = userInfoResponse.data.data
                console.log('GymDashboard - 获取到的完整用户信息:', userData)
              }
            }
          } catch (userInfoError) {
            console.warn('GymDashboard - 获取用户详细信息失败，使用登录响应中的数据:', userInfoError)
          }

          localStorage.setItem('userInfo', JSON.stringify(userData))
          localStorage.setItem('userId', userData.userId || userData.id)

          // 检查登录响应中的所有可能的积分字段
          console.log('登录响应中的用户数据结构:', Object.keys(userData))
          console.log('登录响应中的可能积分字段:', {
            uPoints: userData.uPoints,
            points: userData.points,
            score: userData.score,
            totalPoints: userData.totalPoints,
            userScore: userData.userScore
          })

          // 尝试从登录响应中获取积分，使用更多可能的字段名
          userPoints.value = userData.uPoints || userData.points || userData.score || userData.totalPoints || userData.userScore || 0
          console.log('登录成功后从响应中直接获取的积分:', userPoints.value)

          userStore.token = userData.token || 'user-logged-in'
          userStore.isLoggedIn = true
          userStore.userInfo = userData
          isLoggedIn.value = true

          console.log('GymDashboard - 登录状态已更新:', { storeLoggedIn: userStore.isLoggedIn, localLoggedIn: isLoggedIn.value })

          // 登录成功后立即从API获取最新的积分数据
          console.log('登录成功后调用fetchUserMemberCard获取最新积分')
          await fetchUserMemberCard()
          console.log('fetchUserMemberCard调用完成，最终积分:', userPoints.value)
          console.log('登录成功后会员卡剩余天数:', latestValidCard.value.remainingDays)
          
          // 检查剩余天数是否为零
          if (latestValidCard.value.remainingDays === 0) {
            console.log('检测到用户没有有效会员卡，显示提示')
            // 这里可以添加提示信息，例如通过alert或其他通知机制
            alert('您当前没有有效会员卡，请购买会员卡以享受会员服务')
          }

          showLoginModal.value = false
          loginForm.value.mobile = ''
          loginForm.value.password = ''

          router.replace('/user/dashboard')
        } else {
          errorMessage.value = response.data.message || '登录失败'
        }
      } catch (error) {
        console.error('登录失败:', error)

        if (error.response && error.response.data) {
          errorMessage.value = error.response.data.message || '登录失败，请检查手机号和密码'
        } else if (error.code === 'ECONNREFUSED' || error.message?.includes('ECONNREFUSED')) {
          errorMessage.value = '后端服务暂不可用，请检查服务是否启动'
        } else if (error.request) {
          errorMessage.value = '无法连接到服务器，请检查网络连接'
        } else {
          errorMessage.value = '登录过程中发生错误，请稍后重试'
        }
      }
    }

    // 处理注册
    const handleRegister = async () => {
      console.log('GymDashboard - 处理注册')
      registerErrorMessage.value = ''

      if (!registerForm.value.mobile.trim()) {
        registerErrorMessage.value = '请输入手机号'
        return
      }

      if (!registerForm.value.password.trim()) {
        registerErrorMessage.value = '请输入密码'
        return
      }

      if (!registerForm.value.nickname.trim()) {
        registerErrorMessage.value = '请输入昵称'
        return
      }

      if (registerForm.value.password.length < 6) {
        registerErrorMessage.value = '密码长度至少6位'
        return
      }

      try {
        const response = await axios.post('/api/users/register', {
          mobile: registerForm.value.mobile,
          password: registerForm.value.password,
          nickname: registerForm.value.nickname
        })

        if (response.data && response.data.success) {
          try {
            const loginResponse = await axios.post('/api/users/login', {
              mobile: registerForm.value.mobile,
              password: registerForm.value.password
            })

            if (loginResponse.data && loginResponse.data.success) {
              let userData = loginResponse.data.data

              localStorage.setItem('userToken', userData.token || 'user-registered-token')

              try {
                const userId = userData.userId || userData.id
                if (userId) {
                  console.log('GymDashboard - 注册后调用getUserInfo获取最新用户信息，用户ID:', userId)
                  const userInfoResponse = await axios.get(`/api/users/${userId}`)

                  if (userInfoResponse.data && userInfoResponse.data.success) {
                    userData = userInfoResponse.data.data
                    console.log('GymDashboard - 注册后获取到的完整用户信息:', userData)
                  }
                }
              } catch (userInfoError) {
                console.warn('GymDashboard - 注册后获取用户详细信息失败，使用登录响应中的数据:', userInfoError)
              }

              localStorage.setItem('userInfo', JSON.stringify(userData))
              localStorage.setItem('userId', userData.userId || userData.id)

              userStore.token = userData.token || 'user-registered-token'
              userStore.isLoggedIn = true
              userStore.userInfo = userData
              isLoggedIn.value = true

              console.log('GymDashboard - 注册后登录状态已更新:', { storeLoggedIn: userStore.isLoggedIn, localLoggedIn: isLoggedIn.value })

              showRegisterModal.value = false
              registerForm.value.mobile = ''
              registerForm.value.password = ''
              registerForm.value.nickname = ''

              router.replace('/user/dashboard')
            } else {
              registerErrorMessage.value = '注册成功，但自动登录失败，请手动登录'
            }
          } catch (loginError) {
            console.error('自动登录失败:', loginError)
            registerErrorMessage.value = '注册成功，但自动登录失败，请手动登录'
          }
        } else {
          registerErrorMessage.value = response.data.message || '注册失败'
        }
      } catch (error) {
        console.error('注册失败:', error)

        if (error.response && error.response.data) {
          registerErrorMessage.value = error.response.data.message || '注册失败，请稍后重试'
        } else if (error.code === 'ECONNREFUSED' || error.message?.includes('ECONNREFUSED')) {
          registerErrorMessage.value = '后端服务暂不可用，请检查服务是否启动'
        } else if (error.request) {
          registerErrorMessage.value = '无法连接到服务器，请检查网络连接'
        } else {
          registerErrorMessage.value = '注册过程中发生错误，请稍后重试'
        }
      }
    }

    // 跳转到课程列表
    const goToCourseList = () => {
      console.log('=========== goToCourseList 执行 ===========');
      router.push('/course/list')
    }

    // 排行榜搜索关键词
    const rankingSearchKeyword = ref('')

    // 过滤后的排行榜数据
    const filteredRanking = computed(() => {
      if (!rankingSearchKeyword.value) {
        return userRanking.value
      }
      const keyword = rankingSearchKeyword.value.toLowerCase()
      return userRanking.value.filter(user =>
          (user.uNickname || '匿名用户').toLowerCase().includes(keyword)
      )
    })

    // 过滤排行榜
    const filterRanking = () => {
      // 计算属性会自动更新
    }

    // 跳转到教练列表
    const goToCoachList = () => {
      console.log('=========== goToCoachList 执行 ===========');
      router.push('/coach/list')
    }

    onMounted(async () => {
      console.log('GymDashboard 组件已加载')

      const token = localStorage.getItem('userToken')
      const userInfoStr = localStorage.getItem('userInfo')
      const userId = localStorage.getItem('userId')

      // 初始化时直接设置为0，稍后通过fetchUserMemberCard从后端获取真实积分
      userPoints.value = 0

      console.log('GymDashboard - 初始localStorage数据:', { token, hasUserInfo: !!userInfoStr, userId })

      if (token) {
        userStore.token = token
        userStore.isLoggedIn = true
        if (userInfoStr) {
          try {
            userStore.userInfo = JSON.parse(userInfoStr)
          } catch (e) {
            console.error('解析userInfo失败:', e)
          }
        }
        console.log('GymDashboard - 初始同步后store状态:', { storeLoggedIn: userStore.isLoggedIn })
      }

      await checkAndValidateLoginStatus()

      fetchMemberCardTypes()

      fetchUpcomingCourses()

      fetchUserRanking()

      document.documentElement.style.overflow = 'hidden'
      document.body.style.overflow = 'hidden'
      document.body.style.position = 'fixed'
      document.body.style.width = '100%'
    })

    onUnmounted(() => {
      document.documentElement.style.overflow = ''
      document.body.style.overflow = ''
      document.body.style.position = ''
      document.body.style.width = ''
    })

    return {
      showLoginModal,
      showRegisterModal,
      showAnnouncementsModal,
      showAnnouncementDetailModal,
      loginForm,
      registerForm,
      errorMessage,
      registerErrorMessage,
      rememberMe,
      searchKeyword,
      announcements,
      filteredAnnouncements,
      currentAnnouncement,
      loadingAnnouncements,
      announcementError,
      upcomingCourses,
      loadingCourses,
      userRanking,
      loadingRanking,
      rankingSearchKeyword,
      filteredRanking,
      filterRanking,
      memberCardTypes,
      isLoggedIn,
      userMemberCard,
      loadingMemberCard,
      userPoints,
      userValidCards,
      latestValidCard,
      goToAdminLogin: goToAdminLoginNewTab,
      handleLogin,
      handleRegister,
      goToCourseList,
      goToCoachList,
      goToCourseDetail,
      showAnnouncements,
      viewAnnouncementDetail,
      getTypeClass,
      getTypeText,
      getContentPreview,
      formatDate,
      formatCourseTime,
      formatExpireDate,
      getMemberLevel,
      getLevelProgress,
      getNextLevel,
      getLevelClass,
      getRankingNumber,
      getCardPoints,
      getCardTypeClass,
      getCardIcon,
      getRemainingDays,
      getCardDuration,
      filterAnnouncements,
      handleReservation,
      showMemberCardModal,
      showPurchaseSuccess,
      cardOptions,
      purchaseMemberCard,
      handlePurchaseConfirm,
      goToMemberCardPurchase
    }
  }
}
</script>

<style scoped>
/* 新增会员信息样式 */
.membership-info {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding: 1rem 0;
}

/* 新增会员信息容器样式 */
.membership-info-container {
  margin-bottom: 1rem;
  height: 140px; /* 固定高度，确保有卡和无卡状态下大小一致 */
}

/* 会员卡信息框 - 包含剩余天数、到期日期和按钮 */
.card-info-box {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  padding: 0.8rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
  height: 100%;
  box-sizing: border-box;
  position: relative;
}

/* 确保会员卡片内部有合适的布局 */
.member-card-scrollable {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}

/* 横向排列剩余天数和到期日期 */
.card-info-row {
  display: flex;
  justify-content: space-between;
  gap: 0.8rem;
  align-items: stretch;
}

/* 剩余天数样式 - 调整大小和对齐 */
.remaining-days-section {
  flex: 1;
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.remaining-days-value {
  font-size: 1.2rem;
  font-weight: bold;
  color: #4facfe;
  text-shadow: 0 2px 4px rgba(79, 172, 254, 0.3);
  margin-bottom: 0.1rem;
  line-height: 1.1;
}

.remaining-days-label {
  font-size: 0.7rem;
  color: #cbd5e0;
}

/* 到期日期样式 - 与剩余天数保持一致，但增加按钮区域 */
.expiry-date-section {
  flex: 1;
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.3rem;
}

.expiry-date-value {
  font-size: 1.2rem;
  font-weight: bold;
  color: #4facfe;
  text-shadow: 0 2px 4px rgba(79, 172, 254, 0.3);
  margin-bottom: 0.1rem;
  line-height: 1.1;
  word-break: break-word;
}

.expiry-date-label {
  font-size: 0.7rem;
  color: #cbd5e0;
}

/* 迷你按钮样式 - 用于到期日期下方的购买/续费按钮 */
.mini-btn {
  padding: 0.3rem 0.6rem !important;
  font-size: 0.7rem !important;
  border-radius: 15px !important;
  gap: 0.2rem !important;
  box-shadow: 0 2px 6px rgba(72, 187, 120, 0.3) !important;
  margin-top: 0.2rem !important;
  width: auto !important;
  max-width: 100%;
  margin-left: auto;
  margin-right: auto;
}

/* 右上角按钮样式 */
.card-info-box .absolute {
  position: absolute;
}

.card-info-box .top-2 {
  top: 0.5rem;
}

.card-info-box .right-2 {
  right: 0.5rem;
}

.mini-btn:hover {
  transform: translateY(-1px) !important;
  box-shadow: 0 3px 8px rgba(72, 187, 120, 0.4) !important;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .card-info-row {
    flex-direction: column;
    gap: 0.5rem;
  }

  .remaining-days-value,
  .expiry-date-value {
    font-size: 1.1rem;
  }

  .membership-info-container {
    height: 130px;
  }
}

/* 无卡状态内容 */
.no-card-content {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  flex: 1;
}

.no-card-content .no-card-icon i {
  font-size: 1.5rem;
  margin-bottom: 0.4rem;
}

.no-card-content .no-card-text {
  font-size: 0.9rem;
  margin: 0;
}

.membership-status {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
}

.remaining-days-section {
  text-align: center;
  padding: 1rem;
}

.remaining-days-value {
  font-size: 3.5rem;
  font-weight: bold;
  color: #fbbf24;
  line-height: 1;
  margin-bottom: 0.5rem;
  text-shadow: 0 2px 8px rgba(251, 191, 36, 0.3);
  background: linear-gradient(135deg, #fbbf24, #f59e0b);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.remaining-days-label {
  font-size: 1rem;
  color: #94a3b8;
  font-weight: 500;
}

/* 旧的到期日期样式已删除，使用新的并排样式 */

.card-type-section {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 0.8rem;
  background: rgba(255, 255, 255, 0.03);
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.05);
}

.multiple-cards-notice {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.8rem;
  background: rgba(79, 172, 254, 0.1);
  border-radius: 8px;
  border: 1px solid rgba(79, 172, 254, 0.2);
  font-size: 0.8rem;
  color: #4facfe;
}

.multiple-cards-notice i {
  font-size: 0.9rem;
}

/* 会员卡购买模态框样式 */
.member-card-modal {
  width: 90%;
  max-width: 500px;
  max-height: 80vh;
  overflow-y: auto;
}

.member-card-options {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.error-message {
  background-color: #ffebee;
  color: #c62828;
  padding: 10px 15px;
  border-radius: 5px;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  font-size: 14px;
}

.error-message i {
  margin-right: 8px;
}

/* 成功提示样式 */
.success-message {
  background-color: #e8f5e9;
  color: #2e7d32;
  padding: 10px 15px;
  border-radius: 5px;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  font-size: 14px;
  border: 1px solid #c8e6c9;
}

.success-message i {
  margin-right: 8px;
  font-size: 16px;
}

/* 下拉滑动条样式 - 与排行榜一致 */
.scrollable-list {
  overflow-y: auto;
  max-height: 350px;
  margin: 0;
  padding: 0;
  padding-right: 8px;
}

.scrollable-list::-webkit-scrollbar {
  width: 6px;
}

.scrollable-list::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 3px;
}

.scrollable-list::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 3px;
}

.scrollable-list::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.3);
}

/* 成功提示样式 */
.toast {
  position: fixed;
  top: 20px;
  right: 20px;
  padding: 12px 20px;
  border-radius: 8px;
  color: white;
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 1000;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  animation: slideIn 0.3s ease-out;
}

.toast.success {
  background: linear-gradient(135deg, #10b981 0%, #059669 100%);
}

@keyframes slideIn {
  from {
    transform: translateX(100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.card-option {
  border-radius: 12px;
  padding: 1.2rem;
  text-align: center;
  transition: transform 0.2s, box-shadow 0.2s;
  border: 2px solid transparent;
}

.card-option:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
  border-color: #4CAF50;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.card-header h4 {
  margin: 0;
  color: #ffffff;
  font-size: 1.2rem;
}

.points-badge {
  background-color: #4CAF50;
  color: white;
  padding: 0.3rem 0.8rem;
  border-radius: 15px;
  font-size: 0.9rem;
  font-weight: bold;
}

.card-price {
  margin: 1rem 0;
  font-size: 2rem;
  font-weight: bold;
  color: #ffffff;
}

.card-price .currency {
  font-size: 1.2rem;
  vertical-align: top;
}

.purchase-btn {
  background: linear-gradient(135deg, #4CAF50, #45a049);
  color: white;
  border: none;
  padding: 0.8rem 2rem;
  border-radius: 25px;
  font-size: 1rem;
  font-weight: bold;
  cursor: pointer;
  transition: background 0.3s;
  margin-top: 1rem;
}

.purchase-btn:hover {
  background: linear-gradient(135deg, #45a049, #3d8b40);
}

/* 会员卡信息美化样式 - 优化版 */
.balance-info-alone {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 350px; /* 确保最小高度 */
}

/* 加载状态样式 */
.loading-content {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  min-height: 200px;
}

/* 会员卡头部区域 */
.card-header-section {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 1.2rem;
}

/* 确保会员卡片滑动区域有足够的高度和内边距 */
.member-card-scrollable {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  min-height: 200px; /* 最小高度确保内容可见 */
  max-height: 350px;
  padding-right: 8px;
  margin-right: -8px;
  margin-bottom: 0.3rem;
  padding-bottom: 10px;
  gap: 0;
}

.card-type-badge {
  padding: 0.5rem 1rem;
  border-radius: 20px;
  font-size: 0.85rem;
  font-weight: 600;
  color: white;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.card-status-indicator {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.8rem;
  border-radius: 15px;
  font-size: 0.75rem;
  font-weight: 500;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.card-status-indicator.active {
  background: rgba(72, 187, 120, 0.2);
  border-color: rgba(72, 187, 120, 0.3);
  color: #48bb78;
}

.card-status-indicator:not(.active) {
  background: rgba(245, 101, 101, 0.2);
  border-color: rgba(245, 101, 101, 0.3);
  color: #f56565;
}

/* 优化无会员卡状态 */
.no-valid-card {
  text-align: center;
  padding: 1.5rem 1rem;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  border: 2px dashed rgba(255, 255, 255, 0.1);
  min-height: 120px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  flex: 1;
}

.no-card-icon {
  width: 50px;
  height: 50px;
  margin: 0 auto 0.8rem;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  color: #cbd5e0;
}

.no-card-text {
  color: #94a3b8;
  font-size: 0.9rem;
  margin: 0;
}

/* 优化积分信息区域 */
.user-points-info {
  background: linear-gradient(135deg, rgba(79, 172, 254, 0.1) 0%, rgba(0, 242, 254, 0.05) 100%);
  border-radius: 12px;
  padding: 1rem;
  border: 1px solid rgba(79, 172, 254, 0.2);
  min-height: 100px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin-top: 0.5rem;
}

/* 优化会员卡滑动区域的滚动条样式 */
.member-card-scrollable::-webkit-scrollbar {
  width: 6px;
}

.member-card-scrollable::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 3px;
}

.member-card-scrollable::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 3px;
}

.member-card-scrollable::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.3);
}

/* 响应式调整 */
@media (max-width: 768px) {
  .balance-info-alone {
    min-height: 320px;
  }

  .member-card-scrollable {
    max-height: calc(100% - 60px);
    gap: 1rem;
  }

  .card-actions-scrollable {
    min-height: 55px;
  }

  .card-actions-scrollable .btn {
    padding: 0.6rem 1rem;
    font-size: 0.8rem;
  }

  .balance-amount {
    font-size: 1.8rem;
  }

  .points-value {
    font-size: 1.4rem;
  }

  .no-valid-card {
    padding: 1rem;
    min-height: 100px;
  }

  .no-card-icon {
    width: 40px;
    height: 40px;
    font-size: 1.1rem;
    margin-bottom: 0.6rem;
  }

  /* 移动端响应式调整 */
  .remaining-days-value {
    font-size: 2.8rem;
  }

  /* 响应式样式已在新的并排样式中包含 */
}

@media (max-width: 480px) {
  .balance-info-alone {
    min-height: 300px;
  }

  .member-card-scrollable {
    max-height: calc(100% - 55px);
  }

  .card-actions-scrollable {
    min-height: 50px;
  }

  .balance-amount {
    font-size: 1.6rem;
  }
}

.points-header {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1rem;
  color: #4facfe;
  font-weight: 600;
  font-size: 0.95rem;
}

.points-header i {
  font-size: 1rem;
}

.points-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.points-value-section {
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
}

/* 优化积分显示 */
.points-value {
  font-size: 1.6rem;
  font-weight: bold;
  color: #f8fafc;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
  line-height: 1;
}

.points-unit {
  font-size: 0.8rem;
  color: #cbd5e0;
}

.level-section {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: flex-end;
  flex: 1;
  max-width: 120px;
}

.member-level-badge {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.8rem;
  border-radius: 15px;
  font-size: 0.75rem;
  font-weight: 600;
  color: white;
  white-space: nowrap;
}

.member-level-badge i {
  font-size: 0.7rem;
}

/* 优化等级进度 */
.level-progress {
  width: 100%;
}

.progress-bar {
  width: 100%;
  height: 3px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 2px;
  overflow: hidden;
  margin-bottom: 0.2rem;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #4facfe, #00f2fe);
  border-radius: 2px;
  transition: width 0.5s ease;
}

.progress-text {
  font-size: 0.65rem;
  color: #94a3b8;
  white-space: nowrap;
}

/* 按钮美化 */
.purchase-btn-primary {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  color: white;
  border: none;
  padding: 0.5rem 1rem;
  border-radius: 20px;
  font-weight: 600;
  font-size: 0.8rem;
  cursor: pointer;
  transition: all 0.3s ease;
  box-shadow: 0 3px 10px rgba(79, 172, 254, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  white-space: nowrap;
}

.purchase-btn-primary:hover {
  transform: translateY(-1px);
  box-shadow: 0 5px 15px rgba(79, 172, 254, 0.4);
  background: linear-gradient(135deg, #3a9df8 0%, #00d9e3 100%);
}

.renew-btn {
  background: linear-gradient(135deg, #48bb78 0%, #38a169 100%);
  color: white;
  border: none;
  padding: 0.6rem 1.2rem;
  border-radius: 20px;
  font-weight: 600;
  font-size: 0.8rem;
  cursor: pointer;
  transition: all 0.3s ease;
  box-shadow: 0 3px 10px rgba(72, 187, 120, 0.3);
  display: flex;
  align-items: center;
  gap: 0.4rem;
  justify-content: center;
  margin-top: auto;
}

.renew-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 5px 15px rgba(72, 187, 120, 0.4);
  background: linear-gradient(135deg, #3ea76d 0%, #2f855a 100%);
}

/* 等级颜色分类 */
.member-level-badge:not([class*="level-"]) {
  background: linear-gradient(135deg, #a0aec0, #718096);
}

.member-level-badge.level-初级会员 {
  background: linear-gradient(135deg, #48bb78, #38a169);
}

.member-level-badge.level-中级会员 {
  background: linear-gradient(135deg, #ed8936, #dd6b20);
}

.member-level-badge.level-高级会员 {
  background: linear-gradient(135deg, #9f7aea, #805ad5);
}

/* 会员卡类型容器 */
.card-types-container {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.card-types-list {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
  margin-bottom: 1rem;
}

.card-types-list.ranking-list {
  list-style: none;
  padding: 0;
  margin: 0;
  flex: 1;
  overflow-y: auto;
  max-height: 280px;
}

/* 会员卡项样式 */
.card-type-item {
  display: flex;
  align-items: center;
  padding: 0.8rem;
  border-radius: 12px;
  transition: all 0.3s ease;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
}

.card-type-item:hover {
  border-color: rgba(255, 255, 255, 0.2);
  background: rgba(255, 255, 255, 0.08);
  transform: translateY(-1px);
}

/* 不同类型卡的样式 */
.card-type-item.month-card,
.card-type-badge.month-card {
  background: linear-gradient(135deg, rgba(102, 126, 234, 0.15) 0%, rgba(118, 75, 162, 0.1) 100%);
  border: 1px solid rgba(102, 126, 234, 0.2);
}

.card-type-item.season-card,
.card-type-badge.season-card {
  background: linear-gradient(135deg, rgba(240, 147, 251, 0.15) 0%, rgba(245, 87, 108, 0.1) 100%);
  border: 1px solid rgba(240, 147, 251, 0.2);
}

.card-type-item.year-card,
.card-type-badge.year-card {
  background: linear-gradient(135deg, rgba(79, 172, 254, 0.15) 0%, rgba(0, 242, 254, 0.1) 100%);
  border: 1px solid rgba(79, 172, 254, 0.2);
}

.card-type-item.default-card,
.card-type-badge.default-card {
  background: linear-gradient(135deg, rgba(255, 193, 7, 0.15) 0%, rgba(255, 152, 0, 0.1) 100%);
  border: 1px solid rgba(255, 193, 7, 0.2);
}

.card-type-icon {
  width: 40px;
  height: 40px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 0.8rem;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.card-type-icon i {
  font-size: 1.2rem;
  color: rgba(255, 255, 255, 0.8);
}

.month-card .card-type-icon {
  background: rgba(102, 126, 234, 0.2);
  border-color: rgba(102, 126, 234, 0.3);
}

.season-card .card-type-icon {
  background: rgba(240, 147, 251, 0.2);
  border-color: rgba(240, 147, 251, 0.3);
}

.year-card .card-type-icon {
  background: rgba(79, 172, 254, 0.2);
  border-color: rgba(79, 172, 254, 0.3);
}

.default-card .card-type-icon {
  background: rgba(255, 193, 7, 0.2);
  border-color: rgba(255, 193, 7, 0.3);
}

.card-type-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0; /* 允许内容溢出时自动缩小 */
}

.card-type-item {
  display: flex;
  align-items: center;
  padding: 0.8rem;
  border-radius: 12px;
  transition: all 0.3s ease;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  gap: 0.8rem;
}

.card-type-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.4rem;
}

.card-type-name {
  color: #f8fafc;
  font-weight: 600;
  font-size: 0.95rem;
}

.card-type-price {
  color: #fbbf24;
  font-weight: 700;
  font-size: 1rem;
}

.card-type-details {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.8rem;
}

.card-duration {
  color: #94a3b8;
}

.card-points {
  color: #10b981;
  font-weight: 500;
}

/* 登录提示区域 */
.login-prompt {
  text-align: center;
  padding: 1rem 0 0.5rem 0;
  margin-top: auto;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.login-prompt .expire-date {
  margin: 0;
  color: #94a3b8;
  font-size: 0.9rem;
  line-height: 1.4;
  padding-top: 0.8rem;
}

/* 其余样式保持不变 */
.gym-dashboard {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
  Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
  color: #333;
  height: 100vh;
  background-color: #1a202c;
  background-image:
      radial-gradient(rgba(246, 173, 85, 0.05) 2px, transparent 2px),
      radial-gradient(rgba(45, 55, 72, 0.03) 2px, transparent 2px);
  background-size: 50px 50px;
  background-position: 0 0, 25px 25px;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* 排行榜卡片头部带搜索框 */
.card-header-with-search {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
  position: relative;
}

.card-header-with-search h2 {
  margin-bottom: 0;
}

.ranking-search-box {
  width: 138px;
  margin-bottom: 10px;
}

.ranking-search-box .input-with-icon {
  position: relative;
  display: flex;
  align-items: center;
}

.ranking-search-box .input-with-icon i {
  position: absolute;
  left: 0.7rem;
  color: #94a3b8;
  z-index: 1;
  font-size: 0.8rem;
}

.ranking-search-box .input-with-icon input {
  width: 100%;
  padding: 0.4rem 0.6rem 0.4rem 1.8rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 15px;
  font-size: 0.8rem;
  background: rgba(255, 255, 255, 0.1);
  color: #f8fafc;
  transition: all 0.3s ease;
  height: 32px;
}

.ranking-search-box .input-with-icon input::placeholder {
  color: #94a3b8;
  font-size: 0.8rem;
}

.ranking-search-box .input-with-icon input:focus {
  outline: none;
  border-color: rgba(102, 126, 234, 0.6);
  background: rgba(255, 255, 255, 0.15);
  box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
}

/* 排行榜内容区域 */
.ranking-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.member-level {
  font-size: 0.75rem;
  color: #94a3b8;
}

/* 自定义滚动条样式 */
.ranking-list::-webkit-scrollbar {
  width: 6px;
}

.ranking-list::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 3px;
}

.ranking-list::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 3px;
}

.ranking-list::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.3);
}

/* 排名数字样式调整 - 放在左边 */
.ranking-number {
  color: #fbbf24;
  font-weight: bold;
  font-size: 1.1rem;
  min-width: 25px;
  text-align: center;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

/* 排名前三的特殊样式 */
.rank-item:nth-child(1) .ranking-number {
  color: #ffd700;
  font-size: 1.3rem;
}

.rank-item:nth-child(2) .ranking-number {
  color: #c0c0c0;
  font-size: 1.2rem;
}

.rank-item:nth-child(3) .ranking-number {
  color: #cd7f32;
  font-size: 1.1rem;
}

/* 为 logo 添加点击样式 */
.logo {
  cursor: pointer;
  transition: all 0.3s ease;
  padding: 0.3rem 0.5rem;
  border-radius: 6px;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.logo:hover {
  background-color: rgba(255, 255, 255, 0.1);
  transform: scale(1.05);
}

/* 装饰性元素 */
.decorative-element {
  position: absolute;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  filter: blur(100px);
  z-index: 0;
  opacity: 0.3;
}

.top-left {
  top: -100px;
  left: -100px;
  background: linear-gradient(135deg, #f6ad55, #ed8936);
}

.top-right {
  top: -100px;
  right: -100px;
  background: linear-gradient(135deg, #2d3748, #4a5568);
}

.bottom-left {
  bottom: -100px;
  left: -100px;
  background: linear-gradient(135deg, #2d3748, #4a5568);
}

.bottom-right {
  bottom: -100px;
  right: -100px;
  background: linear-gradient(135deg, #f6ad55, #ed8936);
}

/* 模态框样式 - 优化版 */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  backdrop-filter: blur(5px);
  animation: fadeIn 0.3s ease;
}

.modal-content {
  background: white;
  border-radius: 20px;
  padding: 2.5rem;
  width: 90%;
  box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
  animation: slideUp 0.3s ease;
  position: relative;
  overflow: hidden;
}

.modal-content::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(135deg, #f6ad55 0%, #ed8936 100%);
}

.modal-header {
  display: flex;
  align-items: center;
  margin-bottom: 2rem;
  text-align: center;
  flex-direction: column;
}

.modal-icon {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1rem;
  font-size: 1.5rem;
  color: white;
}

.login-modal .modal-icon {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.register-modal .modal-icon {
  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}

.announcements-modal .modal-icon {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}

.announcement-detail-modal .modal-icon {
  background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}

.modal-header h3 {
  margin: 0;
  color: #2d3748;
  font-size: 1.8rem;
  font-weight: 700;
}

.close-btn {
  position: absolute;
  top: 1.5rem;
  right: 1.5rem;
  background: none;
  border: none;
  font-size: 1.8rem;
  cursor: pointer;
  color: #718096;
  padding: 0;
  width: 35px;
  height: 35px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  transition: all 0.2s ease;
}

.close-btn:hover {
  color: #4a5568;
  background-color: #f7fafc;
}

.input-with-icon {
  position: relative;
  display: flex;
  align-items: center;
}

.input-with-icon i {
  position: absolute;
  left: 1rem;
  color: #a0aec0;
  z-index: 1;
  font-size: 1rem;
}

.input-with-icon input {
  width: 100%;
  padding: 1rem 1rem 1rem 3rem;
  border: 2px solid #e2e8f0;
  border-radius: 12px;
  font-size: 1rem;
  transition: all 0.3s ease;
  background-color: #f8fafc;
}

.input-with-icon input:focus {
  outline: none;
  border-color: #4299e1;
  background-color: white;
  box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);
}

.remember-me input {
  display: none;
}

.remember-me input:checked + .checkmark {
  background: #4299e1;
  border-color: #4299e1;
}

.remember-me input:checked + .checkmark::after {
  content: '✓';
  position: absolute;
  color: white;
  font-size: 0.8rem;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.fitness-motto p {
  margin: 0;
  color: #718096;
  font-size: 0.9rem;
  font-weight: 500;
}

/* 公告搜索框 */
.search-box {
  margin: 0 0 1.5rem 0;
}

.search-box .input-with-icon input {
  border-radius: 25px;
  padding: 0.8rem 1rem 0.8rem 3rem;
  background: #f8fafc;
  border: 2px solid #e2e8f0;
  transition: all 0.3s ease;
}

.search-box .input-with-icon input:focus {
  background: white;
  border-color: #4299e1;
  box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);
}

.search-box .input-with-icon i {
  left: 1.2rem;
  color: #a0aec0;
}

/* 公告列表模态框样式调整 */
.announcements-modal {
  max-width: 900px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
}

.announcements-modal .modal-header {
  margin-bottom: 1rem;
}

.loading-announcements {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 3rem 1rem;
  text-align: center;
}

.loading-spinner {
  font-size: 2rem;
  color: #4a5568;
  margin-bottom: 1rem;
}

.announcement-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 2rem 1rem;
  text-align: center;
  color: #e53e3e;
  background-color: #fed7d7;
  border-radius: 0.375rem;
  margin: 1rem 0;
}

.announcement-error i {
  font-size: 2rem;
  margin-bottom: 0.5rem;
}

.announcement-error button {
  margin-top: 1rem;
  background-color: #e53e3e;
  color: white;
}

.announcement-error button:hover {
  background-color: #c53030;
}

.announcements-list {
  flex: 1;
  overflow-y: auto;
  margin: 0;
}

.announcement-item {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: 1.5rem;
  border: 1px solid #e2e8f0;
  border-radius: 12px;
  margin-bottom: 1rem;
  transition: all 0.3s ease;
  background: #f8fafc;
}

.announcement-item:hover {
  border-color: #cbd5e0;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
  transform: translateY(-2px);
}

.announcement-main {
  flex: 1;
  margin-right: 1.5rem;
}

.announcement-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 1rem;
}

.announcement-title {
  margin: 0;
  font-size: 1.2rem;
  font-weight: 600;
  color: #2d3748;
  flex: 1;
}

.announcement-type {
  padding: 0.3rem 0.8rem;
  border-radius: 15px;
  font-size: 0.8rem;
  font-weight: 600;
  margin-left: 1rem;
  white-space: nowrap;
}

.announcement-content-preview {
  margin: 0 0 1rem 0;
  color: #4a5568;
  font-size: 0.95rem;
  line-height: 1.5;
}

.announcement-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.announcement-date {
  font-size: 0.85rem;
  color: #718096;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.view-detail-btn {
  padding: 0.7rem 1.2rem;
  background: linear-gradient(135deg, #2d3748 0%, #4a5568 100%);
  color: white;
  border: none;
  border-radius: 8px;
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.view-detail-btn:hover {
  background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(45, 55, 72, 0.3);
}

.no-announcements {
  text-align: center;
  padding: 3rem;
  color: #718096;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

.no-announcements i {
  font-size: 3rem;
  opacity: 0.5;
}

/* 静态背景图片 */
.hero-image-static {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: calc(100% + 1px);
  background-image: url('@/assets/images/gym-interior1.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  transform: scale(1);
}

/* 公告详情模态框样式 */
.announcement-detail-modal {
  max-width: 700px;
  max-height: 80vh;
}

.announcement-detail {
  padding: 0.5rem 0;
}

.detail-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 1.5rem;
  padding-bottom: 1rem;
  border-bottom: 2px solid #e2e8f0;
}

.detail-title {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 700;
  color: #2d3748;
  flex: 1;
  margin-right: 1rem;
}

.detail-type {
  padding: 0.4rem 1rem;
  border-radius: 15px;
  font-size: 0.85rem;
  font-weight: 600;
  white-space: nowrap;
}

.detail-meta {
  margin-bottom: 2rem;
}

.detail-date {
  font-size: 0.95rem;
  color: #718096;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.detail-content {
  line-height: 1.7;
  color: #4a5568;
  font-size: 1rem;
}

.detail-content p {
  margin: 0;
}

/* 动画效果 */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* 横幅区域样式 */
.hero-section {
  height: calc(100vh - 100px);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  flex-shrink: 0;
  overflow: hidden;
}

.hero-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0.2) 100%);
  z-index: 1;
}

.hero-content {
  position: relative;
  text-align: center;
  max-width: 800px;
  width: 100%;
  padding: 0 2rem;
  z-index: 2;
  margin-top: -444px;
}

.hero-content h1 {
  font-size: 2.2rem;
  margin-bottom: 0.8rem;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
  font-weight: 700;
}

.hero-subtitle {
  font-size: 1rem;
  margin-bottom: 1.5rem;
  opacity: 0.95;
  font-weight: 300;
}

.hero-buttons {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem;
}

.btn {
  padding: 0.7rem 1.4rem;
  border: none;
  border-radius: 50px;
  cursor: pointer;
  font-weight: 600;
  transition: all 0.3s ease;
  font-size: 0.95rem;
  text-decoration: none;
  display: inline-block;
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
  background: rgba(255, 255, 255, 0.15);
}

.btn.primary {
  background: linear-gradient(135deg,
  rgba(246, 173, 85, 0.1) 0%,
  rgba(237, 137, 54, 0.1) 100%);
  color: white;
  border: 1px solid rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px);
}

.btn.secondary {
  background: linear-gradient(135deg,
  rgba(102, 126, 234, 0.1) 0%,
  rgba(118, 75, 162, 0.1) 100%);
  color: white;
  border: 1px solid rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px);
}

.btn.tertiary {
  background: linear-gradient(135deg,
  rgba(79, 172, 254, 0.1) 0%,
  rgba(0, 242, 254, 0.1) 100%);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px);
}

.btn.tertiary:hover {
  background: rgba(255, 255, 255, 0.1);
}

.btn.small {
  padding: 0.5rem 1rem;
  font-size: 0.85rem;
  background-color: #e2e8f0;
  color: #4a5568;
}

.admin-login-modal .modal-icon {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.admin-motto p {
  margin: 0;
  color: #718096;
  font-size: 0.9rem;
  font-weight: 500;
}

/* 响应式设计调整 */
@media (max-width: 768px) {
  .user-menu {
    flex-direction: column;
    gap: 0.3rem;
  }

  .admin-btn, .login-btn {
    padding: 0.4rem 0.8rem;
    font-size: 0.8rem;
    margin-right: 0;
  }
}

/* 卡片区域样式 - 修改为固定宽度 */
.cards-section {
  display: grid;
  grid-template-columns: repeat(3, 380px);
  justify-content: center;
  gap: 5rem;
  padding: 0 2rem;
  max-width: 1300px;
  margin: -474px auto 0;
  position: relative;
  z-index: 10;
  flex: 1;
  align-content: start;
  min-height: 250px;
}

.card {
  background: rgba(15, 23, 42, 0.8);
  backdrop-filter: blur(25px);
  border-radius: 20px;
  padding: 2rem;
  transition: all 0.4s ease;
  border: 1px solid rgba(255, 255, 255, 0.08);
  min-height: 424px;
  height: 424px;
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
  box-shadow:
      0 25px 50px rgba(0, 0, 0, 0.4),
      inset 0 1px 0 rgba(255, 255, 255, 0.1),
      0 0 0 1px rgba(255, 255, 255, 0.05);
}

.card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
}

/* 为第一个卡片添加特殊背景 */
.card:nth-child(1) {
  background: linear-gradient(135deg,
  rgba(102, 126, 234, 0.15) 0%,
  rgba(118, 75, 162, 0.1) 100%);
  border: 1px solid rgba(102, 126, 234, 0.2);
}

.card:nth-child(2) {
  background: linear-gradient(135deg,
  rgba(240, 147, 251, 0.15) 0%,
  rgba(245, 87, 108, 0.1) 100%);
  border: 1px solid rgba(240, 147, 251, 0.2);
}

.card:nth-child(3) {
  background: linear-gradient(135deg,
  rgba(79, 172, 254, 0.15) 0%,
  rgba(0, 242, 254, 0.1) 100%);
  border: 1px solid rgba(79, 172, 254, 0.2);
}

.card:hover {
  transform: translateY(-8px);
  box-shadow:
      0 35px 60px rgba(0, 0, 0, 0.5),
      inset 0 1px 0 rgba(255, 255, 255, 0.15),
      0 0 0 1px rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.15);
}

/* 优化卡片标题区域 */
.card h2 {
  margin-bottom: 1.2rem;
  font-size: 1.3rem;
  color: #f8fafc;
  font-weight: 700;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  flex-shrink: 0; /* 防止标题被压缩 */
}

.card-subtitle {
  color: #94a3b8;
  font-size: 0.95rem;
  margin-bottom: 1.2rem;
}

/* 优化卡片整体布局 */
.card-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 300px; /* 确保卡片有足够的最小高度 */
}

.card-balance {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  flex: 1;
}

.balance-info {
  flex: 1;
  text-align: right;
}

.balance-label {
  color: #94a3b8;
  font-size: 1rem;
  margin-bottom: 0.5rem;
}

/* 优化余额显示 */
.balance-amount {
  font-size: 2rem;
  font-weight: bold;
  color: #f8fafc;
  margin: 0.5rem 0;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
  background: linear-gradient(135deg, #fbbf24, #f59e0b);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  line-height: 1.2;
}

.expire-date {
  color: rgba(148, 163, 184, 0.8);
  font-size: 0.9rem;
}

.course-item {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: 1rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  transition: all 0.3s ease;
  margin-bottom: 0.8rem;
}

.course-item:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.2);
  transform: translateX(5px);
}

.ranking-list {
  list-style: none;
  padding: 0;
  margin: 0;
  flex: 1;
  overflow-y: auto;
  max-height: 300px;
}

.rank-item {
  display: flex;
  align-items: center;
  padding: 0.8rem 0.5rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  transition: all 0.3s ease;
  gap: 0.8rem;
}

.rank-item:hover {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  margin: 0 -0.2rem;
  padding: 0.8rem 0.7rem;
}

.course-info {
  flex: 1;
  margin-right: 1rem;
}

.course-name {
  margin: 0 0 0.5rem 0;
  font-size: 1rem;
  font-weight: 600;
  color: #f8fafc;
}

.course-time {
  margin: 0 0 0.3rem 0;
  font-size: 0.9rem;
  color: #cbd5e1;
}

.course-details {
  margin: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.8rem;
}

.course-grade {
  background: rgba(255, 255, 255, 0.1);
  color: #cbd5e1;
  padding: 2px 6px;
  border-radius: 4px;
  font-weight: 500;
}

.course-capacity {
  color: #94a3b8;
}

.view-course-btn {
  padding: 8px 16px;
  font-size: 0.8rem;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white !important;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  white-space: nowrap;
  flex-shrink: 0;
  box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}

.view-course-btn:hover {
  background: linear-gradient(135deg, #5a6fd8 0%, #6a67a6 100%);
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
  color: white;
}

.loading-courses,
.no-courses {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 2rem 0;
  color: #94a3b8;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  margin: 1rem 0;
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.loading-courses p,
.no-courses p {
  margin-bottom: 1rem;
}

.upcoming-courses-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.upcoming-courses-list {
  flex: 1;
  overflow-y: auto;
  max-height: 280px;
  padding-right: 8px;
  margin-bottom: 10px;
}

.upcoming-courses-list::-webkit-scrollbar {
  width: 6px;
}

.upcoming-courses-list::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 3px;
}

.upcoming-courses-list::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 3px;
}

.upcoming-courses-list::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.3);
}

.course-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.05);
  transition: all 0.3s ease;
  margin-bottom: 8px;
}

.course-item:hover {
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  transform: translateY(-1px);
}

.course-item:last-child {
  margin-bottom: 0;
}

.course-info {
  flex: 1;
  margin-right: 12px;
}

.course-name {
  margin: 0 0 6px 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: #f8fafc;
  line-height: 1.3;
}

.course-time {
  margin: 0 0 6px 0;
  font-size: 0.85rem;
  color: #cbd5e1;
  display: flex;
  align-items: center;
  gap: 4px;
}

.course-time i {
  color: #94a3b8;
  font-size: 0.8rem;
}

.courses-scroll-indicator i {
  font-size: 0.7rem;
  animation: bounce 2s infinite;
}

@keyframes bounce {
  0%, 20%, 50%, 80%, 100% {
    transform: translateY(0);
  }
  40% {
    transform: translateY(-3px);
  }
  60% {
    transform: translateY(-2px);
  }
}

.loading-courses,
.no-courses {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 2rem 0;
  color: #94a3b8;
}

.loading-courses p,
.no-courses p {
  margin-bottom: 1rem;
}

.ranking-list {
  list-style: none;
  padding: 0;
  margin: 0;
  flex: 1;
  overflow-y: auto;
  max-height: 300px;
}

.rank-item {
  display: flex;
  align-items: center;
  padding: 0.8rem 0.5rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  transition: all 0.3s ease;
  gap: 0.8rem;
}

.rank-item:hover {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  margin: 0 -0.2rem;
  padding: 0.8rem 0.7rem;
}

.rank-item:last-child {
  border-bottom: none;
}

.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid rgba(255, 255, 255, 0.2);
}

.user-info {
  display: flex;
  align-items: center;
  flex: 1;
  gap: 0.8rem;
}

.user-details {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.user-nickname {
  color: #f8fafc;
  font-weight: 600;
  font-size: 0.95rem;
}

.rank-item:hover .arrow {
  transform: translateX(2px);
  color: #94a3b8;
}

.watermark {
  position: fixed;
  bottom: 0.5rem;
  right: 0.5rem;
  color: #cbd5e0;
  font-size: 0.7rem;
  z-index: 10;
}

/* 移动端响应式调整 */
@media (max-width: 768px) {
  .card-header-with-search {
    flex-direction: column;
    align-items: stretch;
    gap: 0.8rem;
  }

  .ranking-search-box {
    width: 100%;
    align-self: flex-end;
    max-width: 150px;
  }

  .rank-item {
    padding: 0.7rem 0.3rem;
    gap: 0.6rem;
  }

  .ranking-number {
    min-width: 22px;
    font-size: 1rem;
  }

  .user-info {
    gap: 0.6rem;
  }

  .avatar {
    width: 35px;
    height: 35px;
  }

  .user-nickname {
    font-size: 0.9rem;
  }
}

/* 响应式设计 */
@media (max-width: 768px) {
  .gym-dashboard {
    min-height: 100vh;
    overflow-x: hidden;
  }

  .hero-section {
    height: 65vh;
  }

  .hero-content h1 {
    font-size: 1.8rem;
  }

  .hero-buttons {
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
  }

  .btn {
    width: 180px;
    padding: 0.6rem 1rem;
  }

  .cards-section {
    grid-template-columns: 1fr;
    padding: 0 1.5rem;
    margin: -40px auto 0;
    gap: 1.5rem;
  }

  .card {
    min-height: 180px;
    padding: 1.2rem;
  }

  .card-balance {
    flex-direction: column;
    text-align: center;
    gap: 1.2rem;
  }

  .balance-info {
    text-align: center;
  }

  .login-btn {
    padding: 0.4rem 0.8rem;
    font-size: 0.8rem;
  }

  .modal-content {
    padding: 2rem;
    margin: 1rem;
  }

  .announcement-item {
    flex-direction: column;
    align-items: stretch;
  }

  .announcement-main {
    margin-right: 0;
    margin-bottom: 1rem;
  }

  .announcement-header {
    flex-direction: column;
    align-items: flex-start;
  }

  .announcement-type {
    margin-left: 0;
    margin-top: 0.5rem;
  }

  .detail-header {
    flex-direction: column;
    align-items: flex-start;
  }

  .detail-type {
    margin-top: 0.5rem;
  }

  .announcements-modal,
  .announcement-detail-modal {
    margin: 1rem;
    max-height: 85vh;
  }

  .course-item {
    flex-direction: column;
    align-items: stretch;
  }

  .course-info {
    margin-right: 0;
    margin-bottom: 1rem;
  }

  .decorative-element {
    width: 150px;
    height: 150px;
  }
}

/* 防止内容溢出 */
@media (max-height: 700px) {
  .hero-section {
    height: calc(65vh - 50px);
  }

  .cards-section {
    margin: -30px auto 0;
  }
}

/* 小屏幕手机调整 */
@media (max-width: 480px) {
  .ranking-list {
    max-height: 250px;
  }

  .ranking-search-box {
    max-width: 130px;
  }

  .ranking-search-box .input-with-icon input {
    padding: 0.35rem 0.5rem 0.35rem 1.6rem;
    font-size: 0.75rem;
    height: 30px;
  }

  .rank-item {
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .user-info {
    flex: 1;
    min-width: 0;
  }
}

/* 下拉滑动条样式 - 与排行榜一致 */
.scrollable-list {
  overflow-y: auto;
  max-height: 250px;
  margin: 0;
  padding: 0;
}

.card-types-list {
  margin: 0;
  padding: 0;
}

.login-prompt {
  text-align: center;
  padding: 2px 0;
  margin: 2px 0 0 0;
  clear: both;
  position: relative;
  z-index: 10;
}

.login-prompt .expire-date {
  margin: 0;
  color: #94a3b8;
  font-size: 0.9rem;
  line-height: 1.4;
  padding-top: 0.8rem;
}

.card-types-list.ranking-list::-webkit-scrollbar {
  width: 6px;
}

.card-types-list.ranking-list::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 3px;
}

.card-types-list.ranking-list::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 3px;
}

.card-types-list.ranking-list::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.3);
}

/* 响应式调整 */
@media (max-width: 768px) {
  .points-content {
    flex-direction: column;
    align-items: stretch;
    gap: 1rem;
  }

  .level-section {
    align-items: stretch;
    max-width: none;
  }

  .card-details-grid {
    grid-template-columns: 1fr;
  }

  .balance-amount {
    font-size: 1.8rem;
  }
}

/* 优化按钮区域 */
.card-actions-scrollable {
  margin-top: 1rem;
  padding-top: 0.8rem;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  justify-content: center;
  padding-bottom: 0.3rem;
  width: 100%;
  min-height: 45px; /* 确保按钮区域有足够高度 */
  align-items: center;
}

.card-actions-scrollable .btn {
  width: 100%;
  max-width: 100%;
  justify-content: center;
  padding: 0.7rem 1.2rem;
  font-size: 0.85rem;
  white-space: nowrap;
  min-height: 40px;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
</style>